
package com.example.quicklaunch;

import android.text.TextUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Search 9-key match until. to check some input match the words or not.
 * 
 * @author yadong.huang
 * @since 2014/02/09
 */

public class Matcher {

    /**
     * Get the number match index , Ex. input 12345 , words 123456 result = 4
     * 
     * @param input
     * @param words
     * @return last match index
     */
    public static int numberMatch(String input, String words) {
        int result = -1;
        if (input == null || words == null) {
            return result;
        }
        if (input.length() > words.length()) {
            return result;
        }
        for (int index = 0; index < input.length(); index++) {
            if (input.charAt(index) != words.charAt(index)) {
                break;
            } else if (index == input.length() - 1) {
                result = index;
            }
        }
        return result;
    }

    /**
     * First letter match check,then add the matched letter to 3rd parameter.
     * ex. arr={234,345,653} input=236 marched=true arr={234,123,123} input=21
     * marched=true
     * 
     * @param arr
     * @param input
     * @param marched A list to save the matched words. Can not be null.
     * @return marched return true otherwise false
     */
    private static boolean headCheck(List<String> arr, String input,
            List<String> marched) {
        // Input length must small than arr.size();
        if (arr.size() < input.length()) {
            return false;
        }
        for (int index = 0; index < input.length(); index++) {
            if (arr.get(index).charAt(0) != input.charAt(index)) {
                // Don't match, clear the matched list.
                marched.clear();
                return false;
            } else {
                // If matched , add to matched list.
                marched.add(arr.get(index));
            }
        }
        return true;
    }

    /**
     * Name match external interface.
     * 
     * @param arr
     * @param input
     * @param marched A list to save the matched words. Can not be null.
     * @return true otherwise false
     */
    public static boolean nameMatch(List<String> arr, String input,
            List<String> marched) {
        if (arr == null || TextUtils.isEmpty(input) || marched == null) {
            MLog.e("Name match parameter check error!!!!!!!"
                    + (arr == null) + " " + TextUtils.isEmpty(input) + " "
                    + (marched == null));
            return false;
        }
        if (headCheck(arr, input, marched)) {
            return true;
        }
        // Check the first word match index.
        int marchIndex[] = headMatch(input.charAt(0), arr);
        return checkWorlds(input, arr, marchIndex, marched);
    }

    /**
     * For digit& letter matched index.
     * marched["123","456"] input 1256 return 0156
     * 因为在marched每个子中间有间隔所以 +1
     * @param input
     * @param marched
     * @return
     */
    public static List<Integer> letterDigitMatch(String input, List<String> marched) {
        List<Integer> matchedIndex = new ArrayList<Integer>();
        for (int listIndex = 0; listIndex < marched.size(); listIndex++) {
            String string = marched.get(listIndex);
            for (int index = input.length(); index >= 1; index--) {
                String subInput = input.substring(0, index);
                if (string.indexOf(subInput) != -1) {
                    int i = 0;
                    for (int tempI = 0; tempI < listIndex; tempI++) {
                        i += marched.get(tempI).length()+1;
                    }
                    int a = i;
                    for (;i < a+index;i++) {
                        matchedIndex.add(i);
                    }
                    input = input.substring(index);
                    break;
                }
            }
        }
        return matchedIndex;
    }

    private static boolean checkHeadMarched(int[] matchedIndex) {
        boolean output = false;
        for (int match : matchedIndex) {
            if (match == 1) {
                output = true;
                break;
            }
        }
        return output;
    }

    /**
     * Check function implements.Check from head to end.
     * 
     * @param input
     * @param worlds
     * @param matchedIndex
     * @param marched
     * @return true otherwise false
     */
    private static boolean checkWorlds(String input, List<String> words,
            int[] matchedIndex, List<String> marched) {
        // If no head first match,return false.
        if (!checkHeadMarched(matchedIndex)) {
            return false;
        }

        List<String> copy = new ArrayList<String>();
        // create a copy from words to operate.
        copy.addAll(words);
        // Current check input text. When checked a word we will remove this
        // word from input.
        String currentInput = null;
        boolean match = false;
        // Traversal all index in first word match.
        for (int index = 0; index < matchedIndex.length; index++) {
            // If the copied list size is end , but input not end,Means checked
            // false.
            if (copy.size() == 0 && !currentInput.isEmpty()
                    || copy.size() <= index) {
                marched.clear();
                if (index == matchedIndex.length - 1) {
                    return false;
                } else {
                    // continue other index match.
                    copy = new ArrayList<String>();
                    copy.addAll(words);
                    continue;
                }
            }
            // 1 means march.
            if (matchedIndex[index] == 1) {
                currentInput = input;
                currentInput = checkWorld(copy.get(index), currentInput);
                marched.add(copy.get(index));
                // If input checked end,means matched.
                if (currentInput == null || currentInput.isEmpty()) {
                    // End marched
                    match = true;
                    break;
                } else {
                    // Continue to check the inside of the word.
                    for (int i = index; i >= 0; i--) {
                        copy.remove(i);
                    }
                    matchedIndex = headMatch(currentInput.charAt(0), copy);
                    match = checkWorlds(currentInput, copy, matchedIndex,
                            marched);
                }
            }
            // If matched we want break the for loop.
            if (match) {
                return match;
            }
        }
        return match;
    }

    /**
     * Check the input match with word then split the word. Ex. word="1234"
     * input="12345" output="5" word="12345" input="123" output=""
     * 
     * @param world
     * @param input
     * @return
     */
    private static String checkWorld(String word, String input) {
        int end = word.length() < input.length() ? word.length() : input
                .length();
        int index;
        for (index = 0; index < end; index++) {
            if (word.charAt(index) == input.charAt(index)) {
                continue;
            } else {
                break;
            }
        }
        return input.substring(index);
    }

    /**
     * First letter match check.
     * 
     * @param marcher
     * @param arrs
     * @return
     */
    private static int[] headMatch(char marcher, List<String> arrs) {
        int outIndex[] = new int[arrs.size()];
        for (int index = 0; index < arrs.size(); index++) {
            if (marcher == arrs.get(index).charAt(0)) {
                outIndex[index] = 1;
            }
        }
        return outIndex;
    }

    /*
     * test code public static void main(String args[]) { List<String> arr = new
     * ArrayList<String>(); { arr.add("53"); arr.add("5486"); arr.add("5864");
     * arr.add("5284"); arr.add("59"); } System.out.println(march(arr,
     * "535458655")); }
     */
}
